import { LogLevel, LogEntry, ConsoleRedirectOptions } from '../types';
import { LogFormatter } from '../utils/logFormatter';

export class ConsoleRedirect {
  private originalConsole: {
    log: typeof console.log;
    error: typeof console.error;
    warn: typeof console.warn;
    info: typeof console.info;
    debug: typeof console.debug;
  };
  
  private isRedirecting = false;
  private loggerCallback: ((entry: LogEntry) => void) | null = null;
  private options: ConsoleRedirectOptions;

  constructor(options: ConsoleRedirectOptions = { preserveConsole: false }) {
    this.options = options;
    
    // 保存原始的console方法
    this.originalConsole = {
      log: console.log.bind(console),
      error: console.error.bind(console),
      warn: console.warn.bind(console),
      info: console.info.bind(console),
      debug: console.debug.bind(console)
    };
  }

  /**
   * 开始重定向控制台输出
   */
  startRedirection(loggerCallback: (entry: LogEntry) => void): void {
    if (this.isRedirecting) {
      console.warn('控制台重定向已经启动');
      return;
    }

    this.loggerCallback = loggerCallback;
    this.isRedirecting = true;

    // 重写console方法
    console.error = this.createRedirectedMethod('ERROR', 'Console');
    console.warn = this.createRedirectedMethod('WARN', 'Console');
    console.log = this.createRedirectedMethod('INFO', 'Console');
    console.info = this.createRedirectedMethod('INFO', 'Console');
    console.debug = this.createRedirectedMethod('DEBUG', 'Console');

    // 设置全局错误处理器来捕获未处理的异常
    this.setupGlobalErrorCapture();

    console.info('控制台输出重定向已启动');
  }

  /**
   * 停止重定向控制台输出
   */
  stopRedirection(): void {
    if (!this.isRedirecting) {
      return;
    }

    // 恢复原始的console方法
    console.log = this.originalConsole.log;
    console.error = this.originalConsole.error;
    console.warn = this.originalConsole.warn;
    console.info = this.originalConsole.info;
    console.debug = this.originalConsole.debug;

    // 移除全局错误处理器
    this.removeGlobalErrorCapture();

    this.isRedirecting = false;
    this.loggerCallback = null;

    this.originalConsole.log('控制台输出重定向已停止');
  }

  /**
   * 检查是否正在重定向
   */
  isActive(): boolean {
    return this.isRedirecting;
  }

  /**
   * 直接记录日志条目（绕过重定向）
   */
  logDirect(level: LogLevel, source: string, message: string, data?: any): void {
    if (!this.loggerCallback) {
      return;
    }

    const entry: LogEntry = {
      timestamp: new Date(),
      level,
      source,
      message,
      data
    };

    this.loggerCallback(entry);
  }

  /**
   * 使用原始console方法输出（绕过重定向）
   */
  useOriginalConsole(): typeof console {
    return this.originalConsole;
  }

  /**
   * 创建重定向的console方法
   */
  private createRedirectedMethod(level: LogLevel, defaultSource: string) {
    return (...args: any[]) => {
      try {
        // 检测调用来源
        const source = this.detectCallSource() || defaultSource;
        
        // 格式化消息
        const message = this.formatConsoleArgs(args);
        
        // 如果启用了保留控制台输出，也输出到原始控制台
        if (this.options.preserveConsole) {
          const originalMethod = this.getOriginalMethod(level);
          originalMethod(...args);
        }

        // 发送到日志系统
        if (this.loggerCallback) {
          const entry: LogEntry = {
            timestamp: new Date(),
            level,
            source,
            message,
            data: args.length > 1 ? args.slice(1) : undefined
          };

          this.loggerCallback(entry);
        }
      } catch (error) {
        // 如果重定向过程中出错，回退到原始console
        const originalMethod = this.getOriginalMethod(level);
        originalMethod('重定向失败:', error);
        originalMethod(...args);
      }
    };
  }

  /**
   * 获取对应级别的原始console方法
   */
  private getOriginalMethod(level: LogLevel): (...args: any[]) => void {
    switch (level) {
      case 'ERROR':
        return this.originalConsole.error;
      case 'WARN':
        return this.originalConsole.warn;
      case 'INFO':
        return this.originalConsole.log;
      case 'DEBUG':
        return this.originalConsole.debug;
      default:
        return this.originalConsole.log;
    }
  }

  /**
   * 格式化console参数为字符串
   */
  private formatConsoleArgs(args: any[]): string {
    return args
      .map(arg => {
        if (typeof arg === 'string') {
          return arg;
        } else if (arg instanceof Error) {
          return `${arg.name}: ${arg.message}`;
        } else if (typeof arg === 'object') {
          try {
            return JSON.stringify(arg, null, 0);
          } catch {
            return '[Object]';
          }
        } else {
          return String(arg);
        }
      })
      .join(' ');
  }

  /**
   * 检测调用来源（尝试从堆栈跟踪中获取）
   */
  private detectCallSource(): string | null {
    try {
      const stack = new Error().stack;
      if (!stack) return null;

      const lines = stack.split('\\n');
      // 跳过前几行（Error构造函数、当前方法等）
      for (let i = 3; i < Math.min(lines.length, 8); i++) {
        const line = lines[i];
        
        // 尝试提取文件名和函数名
        const match = line.match(/at\\s+(.+?)\\s+\\(.*[\\\\/](.+?):(\\d+):(\\d+)\\)/);
        if (match) {
          const [, functionName, fileName] = match;
          
          // 过滤掉不相关的调用
          if (fileName.includes('logFormatter') || 
              fileName.includes('consoleRedirect') ||
              fileName.includes('node_modules')) {
            continue;
          }

          // 提取有意义的模块名
          const moduleMatch = fileName.match(/([^/\\\\]+)\\.(ts|js|tsx|jsx)$/);
          if (moduleMatch) {
            const moduleName = moduleMatch[1];
            return functionName !== '<anonymous>' 
              ? `${moduleName}.${functionName}`
              : moduleName;
          }
        }
      }
      
      return null;
    } catch {
      return null;
    }
  }

  /**
   * 设置全局错误捕获
   */
  private setupGlobalErrorCapture(): void {
    // 捕获未处理的Promise拒绝
    process.on('unhandledRejection', this.handleUnhandledRejection);
    
    // 捕获未捕获的异常
    process.on('uncaughtException', this.handleUncaughtException);
  }

  /**
   * 移除全局错误捕获
   */
  private removeGlobalErrorCapture(): void {
    process.removeListener('unhandledRejection', this.handleUnhandledRejection);
    process.removeListener('uncaughtException', this.handleUncaughtException);
  }

  /**
   * 处理未处理的Promise拒绝
   */
  private handleUnhandledRejection = (reason: any, promise: Promise<any>) => {
    if (this.loggerCallback) {
      const entry: LogEntry = {
        timestamp: new Date(),
        level: 'ERROR',
        source: 'UnhandledRejection',
        message: '未处理的Promise拒绝',
        data: {
          reason: reason instanceof Error ? {
            name: reason.name,
            message: reason.message,
            stack: reason.stack
          } : reason,
          promise: promise.toString()
        }
      };

      this.loggerCallback(entry);
    }
  };

  /**
   * 处理未捕获的异常
   */
  private handleUncaughtException = (error: Error) => {
    if (this.loggerCallback) {
      const entry: LogEntry = {
        timestamp: new Date(),
        level: 'ERROR',
        source: 'UncaughtException',
        message: '未捕获的异常',
        data: {
          name: error.name,
          message: error.message,
          stack: error.stack
        }
      };

      this.loggerCallback(entry);
    }

    // 对于未捕获的异常，我们仍然需要退出进程
    // 但是给日志系统一点时间来写入
    setTimeout(() => {
      process.exit(1);
    }, 100);
  };

  /**
   * 创建特定来源的日志记录器
   */
  createSourceLogger(source: string) {
    return {
      error: (message: string, data?: any) => this.logDirect('ERROR', source, message, data),
      warn: (message: string, data?: any) => this.logDirect('WARN', source, message, data),
      info: (message: string, data?: any) => this.logDirect('INFO', source, message, data),
      debug: (message: string, data?: any) => this.logDirect('DEBUG', source, message, data),
      log: (message: string, data?: any) => this.logDirect('INFO', source, message, data)
    };
  }

  /**
   * 获取重定向统计信息
   */
  getStats(): {
    isRedirecting: boolean;
    preserveConsole: boolean;
    hasLoggerCallback: boolean;
  } {
    return {
      isRedirecting: this.isRedirecting,
      preserveConsole: this.options.preserveConsole,
      hasLoggerCallback: this.loggerCallback !== null
    };
  }
}